#include "GMK80Writer.h"


GMK80Writer::GMK80Writer(gameData* dataStructure) {
	this->dataContainer = dataStructure; //Set the structure that stores the game data
}

void GMK80Writer::log(const char* format, ...) { //Output a message
	if (verbose) {
		va_list args;
		va_start( args, format );
		vprintf(format, args);
		va_end( args );
	}
}

WRITESTATUS GMK80Writer::writeData(dataStream* stream, bool verbose) { //Write the data to a dataStream
	this->verbose = verbose;
	log ("Writing Header...\n");
	stream->write<int>(GMK80MAGICNUMBER); //Write the magic number
	stream->write<int>(800); //Version number
	stream->write<int>(this->dataContainer->gameID); //Write the Game ID
	for (int i=0; i<16; i++) { //Fill the 16 unknoen bytes
		stream->writeByte(0x00); //Write a byte
	}

	stream->write<int>(800);
	writeGameSettings(stream,&this->dataContainer->gameSettings);

	log ("Writing Triggers...\n");
	stream->write<int>(800); //GM Version needed for triggers
	stream->write<int>(this->dataContainer->Triggers.size()); //Write the number of triggers
	for(unsigned int i=0; i<this->dataContainer->Triggers.size(); i++) { //for each trigger
		writeTrigger(stream,this->dataContainer->Triggers[i]);
	}
	stream->write<double>(this->dataContainer->triggersChanged); //Write the last time triggers were changed

	log("Writing Constants...\n");
	stream->write<int>(800); //GM version needed for constants
	stream->write<int>(this->dataContainer->Constants.size()); //Write number of constants
	for(unsigned int i=0; i<this->dataContainer->Constants.size(); i++) { //For each constant
		stream->writeString(this->dataContainer->Constants[i]->Name);//Write the constant Name
		stream->writeString(this->dataContainer->Constants[i]->Value); //Write the constant's value
	}
	stream->write<double>(this->dataContainer->constantsChanged); //Last time constants were changed


	///Because of GM's absolutely horrible way of storing resources, we have to do a bunch of work to determine the max ID number, so then we can write 0's for ID's that don't exist.

	log ("Writing Sounds [%i]...\n",this->dataContainer->Sounds.size());
	stream->write<int>(800); //Version needed for this resource
	stream->write<int>(this->dataContainer->Sounds.size()); //Number of the resource
	for(unsigned int i=0; i<this->dataContainer->Sounds.size(); i++) { //For each resource
		if (this->dataContainer->Sounds[i]->exists) {
			writeSound(stream,this->dataContainer->Sounds[i]);
		}else{ //Resource doesnt exist, so we must write a "null" resource
			writeNullResource(stream); //Writes a "nonexistent" resource
		}
	}

	log ("Writing Sprites [%i]...\n",this->dataContainer->Sprites.size());
	stream->write<int>(800); //Version needed for this resource
	stream->write<int>(this->dataContainer->Sprites.size()); //Number of the resource
	for(unsigned int i=0; i<this->dataContainer->Sprites.size(); i++) { //For each resource
		if (this->dataContainer->Sprites[i]->exists) {
			writeSprite(stream,this->dataContainer->Sprites[i]);
		}else{ //Resource doesnt exist, so we must write a "null" resource
			writeNullResource(stream); //Writes a "nonexistent" resource
		}
	}

	log ("Writing Backgrounds [%i]...\n",this->dataContainer->Backgrounds.size());
	stream->write<int>(800); //Version needed for this resource
	stream->write<int>(this->dataContainer->Backgrounds.size()); //Number of the resource
	for(unsigned int i=0; i<this->dataContainer->Backgrounds.size(); i++) { //For each resource
		if (this->dataContainer->Backgrounds[i]->exists) {
			writeBackground(stream,this->dataContainer->Backgrounds[i]);
		}else{ //Resource doesnt exist, so we must write a "null" resource
			writeNullResource(stream); //Writes a "nonexistent" resource
		}
	}

	log ("Writing Paths [%i]...\n",this->dataContainer->Paths.size());
	stream->write<int>(800); //Version needed for this resource
	stream->write<int>(this->dataContainer->Paths.size()); //Number of the resource
	for(unsigned int i=0; i<this->dataContainer->Paths.size(); i++) { //For each resource
		if (this->dataContainer->Paths[i]->exists) {
			writePath(stream,this->dataContainer->Paths[i]);
		}else{ //Resource doesnt exist, so we must write a "null" resource
			writeNullResource(stream); //Writes a "nonexistent" resource
		}
	}

	log ("Writing Scripts [%i]...\n",this->dataContainer->Scripts.size());
	stream->write<int>(800); //Version needed for this resource
	stream->write<int>(this->dataContainer->Scripts.size()); //Number of the resource
	for(unsigned int i=0; i<this->dataContainer->Scripts.size(); i++) { //For each resource
		if (this->dataContainer->Scripts[i]->exists) {
			writeScript(stream,this->dataContainer->Scripts[i]);
		}else{ //Resource doesnt exist, so we must write a "null" resource
			writeNullResource(stream); //Writes a "nonexistent" resource
		}
	}

	log ("Writing Fonts [%i]...\n",this->dataContainer->Fonts.size());
	stream->write<int>(800); //Version needed for this resource
	stream->write<int>(this->dataContainer->Fonts.size()); //Number of the resource
	for(unsigned int i=0; i<this->dataContainer->Fonts.size(); i++) { //For each resource
		if (this->dataContainer->Fonts[i]->exists) {
			writeFont(stream,this->dataContainer->Fonts[i]);
		}else{ //Resource doesnt exist, so we must write a "null" resource
			writeNullResource(stream); //Writes a "nonexistent" resource
		}
	}

	log ("Writing Timelines [%i]...\n",this->dataContainer->Timelines.size());
	stream->write<int>(800); //Version needed for this resource
	stream->write<int>(this->dataContainer->Timelines.size()); //Number of the resource
	for(unsigned int i=0; i<this->dataContainer->Timelines.size(); i++) { //For each resource
		if (this->dataContainer->Timelines[i]->exists) {
			writeTimeline(stream,this->dataContainer->Timelines[i]);
		}else{ //Resource doesnt exist, so we must write a "null" resource
			writeNullResource(stream); //Writes a "nonexistent" resource
		}
	}

	log ("Writing Objects [%i]...\n",this->dataContainer->Objects.size());
	stream->write<int>(800); //Version needed for this resource
	stream->write<int>(this->dataContainer->Objects.size()); //Number of the resource
	for(unsigned int i=0; i<this->dataContainer->Objects.size(); i++) { //For each resource
		if (this->dataContainer->Objects[i]->exists) {
			writeObject(stream,this->dataContainer->Objects[i]);
		}else{ //Resource doesnt exist, so we must write a "null" resource
			writeNullResource(stream); //Writes a "nonexistent" resource
		}
	}

	log ("Writing Rooms [%i]...\n",this->dataContainer->Rooms.size());
	stream->write<int>(800); //Version needed for this resource
	stream->write<int>(this->dataContainer->Rooms.size()); //Number of the resource
	for(unsigned int i=0; i<this->dataContainer->Rooms.size(); i++) { //For each resource
		if (this->dataContainer->Rooms[i]->exists) {
			writeRoom(stream,this->dataContainer->Rooms[i]);
		}else{ //Resource doesnt exist, so we must write a "null" resource
			writeNullResource(stream); //Writes a "nonexistent" resource
		}
	}



	stream->write<int>(this->dataContainer->lastInstancePlaced); //Write the  ID of the last isntance placed
	stream->write<int>(this->dataContainer->lastTilePlaced); //Write the ID of the last tile placed

	log ("Writing Include Files...\n");
	stream->write<int>(800); //GM version requires
	stream->write<int>(this->dataContainer->includedFiles.size()); //Write the number of included files
	for (unsigned int i=0; i<this->dataContainer->includedFiles.size(); i++) { //For each included file
		writeIncludedFile(stream,this->dataContainer->includedFiles[i]); //Write the included file data
	}

	log ("Writing Extensions...\n");
	stream->write<int>(700); //GM version needed for packages
	stream->write<int>(this->dataContainer->Packages.size()); //Write the number of packaged
	for (unsigned int i=0; i<this->dataContainer->Packages.size(); i++) { //For each extension
		stream->writeString(this->dataContainer->Packages[i]); //Write the package name
	}

	log ("Writing Game Information...\n");
	writeGameInformation(stream,&this->dataContainer->gameInformation); //Write the game information

	log ("Writing Library Info...\n");
	stream->write<int>(500); //GM Version required for libraries
	stream->write<int>(this->dataContainer->libCreationCodes.size()); //Number of libraries
	for(unsigned int i=0; i<this->dataContainer->libCreationCodes.size(); i++) { //For each library
		stream->writeString(this->dataContainer->libCreationCodes[i]); //Write the library creation code
	}

	log ("Writing room execution order...\n");
	stream->write<int>(700); //GM version needed for exectution order
	stream->write<int>(this->dataContainer->roomExecutionOrder.size()); //Number of rooms in execution order
	for(unsigned int i=0; i<this->dataContainer->roomExecutionOrder.size(); i++) { //For each room in the execution order
		stream->write<int>(this->dataContainer->roomExecutionOrder[i]); //Write the room ID
	}

	log ("Writing resource tree structure...\n");
	for(unsigned char rootNodes=0; rootNodes<12; rootNodes++) { //For each root node..
		stream->write<int>(this->dataContainer->ResourceTree[rootNodes]->Status); //Status (Primary, group, secondary, etc)
		stream->write<int>(this->dataContainer->ResourceTree[rootNodes]->Group); //Group;
		stream->write<int>(this->dataContainer->ResourceTree[rootNodes]->Index); //Index
		stream->writeString(this->dataContainer->ResourceTree[rootNodes]->Name); //Name

		stream->write<int>(this->dataContainer->ResourceTree[rootNodes]->Contents.size()); //Write the number of child nodes..
		RecursiveTreeWrite(this->dataContainer->ResourceTree[rootNodes],this->dataContainer->ResourceTree[rootNodes]->Contents.size(),stream); //Write all the child nodes

	}

	return WRITE_SUCCESS;
}

void GMK80Writer::RecursiveTreeWrite(ResourceTreeDef* Node, int childrenCount, dataStream* stream)
{
	for (unsigned int i=0; i<childrenCount; i++) { //for each node
		stream->write<int>(Node->Contents[i]->Status); //Status (Primary, group, secondary, etc)
		stream->write<int>(Node->Contents[i]->Group); //Group;
		stream->write<int>(Node->Contents[i]->Index); //Index
		stream->writeString(Node->Contents[i]->Name); //Name

		stream->write<int>(Node->Contents[i]->Contents.size());//Write the number of child nodes..
		RecursiveTreeWrite(Node->Contents[i],Node->Contents[i]->Contents.size(),stream); //Write all the child nodes
	}

}


void GMK80Writer::writeGameSettings(dataStream *data, gameSettingsDef *dataWrite) {
	dataStream * tempData = new dataStream(); //Temporary buffer

	tempData->writeBool4(this->dataContainer->gameSettings.startInFullScreen); //Write weather or not to start in full screen mode
	tempData->writeBool4(this->dataContainer->gameSettings.interpolateColors); //Interpolate colors
	tempData->writeBool4(this->dataContainer->gameSettings.dontDrawBorder); //Dont draw the border in windowed mode
	tempData->writeBool4(this->dataContainer->gameSettings.displayCursor); //Display the cursor?
	tempData->write<int>(this->dataContainer->gameSettings.Scaling); //Scaling
	tempData->writeBool4(this->dataContainer->gameSettings.allowWindowResize); //Allow the player to resize
	tempData->writeBool4(this->dataContainer->gameSettings.alwaysOnTop); //Make the game window always stay on top
	tempData->write<int>(this->dataContainer->gameSettings.colorOutsideRoom); //Color outside room region
	tempData->writeBool4(this->dataContainer->gameSettings.setResolution); //Set the resolution of the screen?
	tempData->write<int>(this->dataContainer->gameSettings.colorDepth); //The color depth
	tempData->write<int>(this->dataContainer->gameSettings.Resolution); //Resolution
	tempData->write<int>(this->dataContainer->gameSettings.Frequency); //Frequency 
	tempData->writeBool4(this->dataContainer->gameSettings.dontShowButtons); //Don't show the buttons in the window caption
	tempData->writeBool4(this->dataContainer->gameSettings.useSync); //Use synchronization to avoid tearing
	tempData->writeBool4(this->dataContainer->gameSettings.disableScreen); //Disable screensavers?
	tempData->writeBool4(this->dataContainer->gameSettings.letF4); //Let F4 do shit.
	tempData->writeBool4(this->dataContainer->gameSettings.letF1); //Let F1 do shit
	tempData->writeBool4(this->dataContainer->gameSettings.letEsc); //Let Esc do shit
	tempData->writeBool4(this->dataContainer->gameSettings.letF5); //Let F5 do shit
	tempData->writeBool4(this->dataContainer->gameSettings.letF9); //Let F9 do shit
	tempData->writeBool4(this->dataContainer->gameSettings.treatCloseAsEsc); //Treat close as esc key
	tempData->write<int>(this->dataContainer->gameSettings.processPriority); //Priority
	tempData->writeBool4(this->dataContainer->gameSettings.freezeUnfocus); //Freeze the game when form losed focus
	tempData->write<int>(this->dataContainer->gameSettings.loadingBar); //Type of loading bar
	if (this->dataContainer->gameSettings.loadingBar==2)
	{//If its a custom loading bar
		if (this->dataContainer->gameSettings.backImageData==NULL)
		{
			tempData->writeBool4(0); //No background image data exists..
		}else{
			tempData->writeBool4(1); //Background image data exists
			this->dataContainer->gameSettings.backImageData->compressData(); //Compress the bitmap
			tempData->write<int>(this->dataContainer->gameSettings.backImageData->getLength()); //Size of compressed bitmap
			tempData->writeBytes(this->dataContainer->gameSettings.backImageData->getBuffer(),this->dataContainer->gameSettings.backImageData->getLength()); //Write the compressed bitmap
		}
		
		if (this->dataContainer->gameSettings.frontImageData==NULL)
		{
			tempData->writeBool4(0); //No background image data exists..
		}else{
			tempData->writeBool4(1); //Background image data exists
			this->dataContainer->gameSettings.frontImageData->compressData(); //Compress the bitmap
			tempData->write<int>(this->dataContainer->gameSettings.frontImageData->getLength()); //Size of compressed bitmap
			tempData->writeBytes(this->dataContainer->gameSettings.frontImageData->getBuffer(),this->dataContainer->gameSettings.frontImageData->getLength()); //Write the compressed bitmap
		}
	}//End If Loading bar type is 2
	tempData->writeBool4(this->dataContainer->gameSettings.customLoadImage);
	if (this->dataContainer->gameSettings.customLoadImage==true)
	{//If we are showing our own image to load the game
		if (this->dataContainer->gameSettings.loadBarImageData==NULL)
		{//If there is no loading image
			tempData->writeBool4(false); //There is no loading image
		}else{
			this->dataContainer->gameSettings.loadBarImageData->compressData(); //Compress the bitmap
			tempData->write<int>(this->dataContainer->gameSettings.loadBarImageData->getLength()); //Size of compressed bitmap
			tempData->writeBytes(this->dataContainer->gameSettings.loadBarImageData->getBuffer(),this->dataContainer->gameSettings.loadBarImageData->getLength()); //Write the compressed bitmap
		}
	}
	tempData->writeBool4(this->dataContainer->gameSettings.imageTransparent); //Make the image partially transparent?
	tempData->write<int>(this->dataContainer->gameSettings.translucentAlpha); //Alpha value 
	tempData->writeBool4(this->dataContainer->gameSettings.scaleProgressBar); //Scale the progress bar?
	tempData->write<int>(this->dataContainer->gameSettings.iconData->getLength()); //Write the size of the icon data
	tempData->writeBytes(this->dataContainer->gameSettings.iconData->getBuffer(),this->dataContainer->gameSettings.iconData->getLength()); //Write icon data
	tempData->writeBool4(this->dataContainer->gameSettings.displayErrors); //Display errors?
	tempData->writeBool4(this->dataContainer->gameSettings.errorLog); //Write an error log?
	tempData->writeBool4(this->dataContainer->gameSettings.abortErrors); //Abort on all errors?
	tempData->writeBool4(this->dataContainer->gameSettings.unitializedVarsZero); //Treat Unitialized variables as 0
	tempData->writeString(this->dataContainer->gameSettings.Author); //Author of game
	tempData->writeString(this->dataContainer->gameSettings.Version); //Version
	tempData->write<double>(this->dataContainer->gameSettings.lastChanged); //Last modified?
	tempData->writeString(this->dataContainer->gameSettings.Information); //Information
	tempData->write<int>(this->dataContainer->gameSettings.majorVersion); //major version
	tempData->write<int>(this->dataContainer->gameSettings.minorVersion); //Minor version
	tempData->write<int>(this->dataContainer->gameSettings.releaseVersion); //Release version
	tempData->write<int>(this->dataContainer->gameSettings.buildVersion); //Build version
	tempData->writeString(this->dataContainer->gameSettings.Company); //Company
	tempData->writeString(this->dataContainer->gameSettings.Product); //Product
	tempData->writeString(this->dataContainer->gameSettings.Copyright); //Copyright string
	tempData->writeString(this->dataContainer->gameSettings.Description); //Desctipyion
	tempData->write<double>(this->dataContainer->gameSettings.lastSettingsChange); //Last time global game settings were changed

	tempData->compressData(); //Compress this whole block
	data->write<int>(tempData->getLength()); //Write length of block
	data->writeBytes(tempData->getBuffer(),tempData->getLength()); //Write the block
	delete tempData; //Delete the buffer
}

void GMK80Writer::writeGameInformation(dataStream *data, gameInfoDef *dataWrite) {
	dataStream * tempData = new dataStream(); //Temporary buffer

	data->write<int>(800); //Version required for Game Info

	tempData->write<int>(this->dataContainer->gameInformation.backgroundColor); //Background color
	tempData->writeBool4(this->dataContainer->gameInformation.seperateWindow); //Show in seperate window?
	tempData->writeString(this->dataContainer->gameInformation.formCaption); //Form caption
	tempData->write<int>(this->dataContainer->gameInformation.positionLeft); //Position left
	tempData->write<int>(this->dataContainer->gameInformation.positionTop); //Position top
	tempData->write<int>(this->dataContainer->gameInformation.positionWidth); //Position width
	tempData->write<int>(this->dataContainer->gameInformation.positionHeight); //Position height
	tempData->writeBool4(this->dataContainer->gameInformation.showWindowBorder); //Show border and caption
	tempData->writeBool4(this->dataContainer->gameInformation.allowResize); //Allow resize?
	tempData->writeBool4(this->dataContainer->gameInformation.stayOnTop); //Stay on top?
	tempData->writeBool4(this->dataContainer->gameInformation.stopGame); //Stop the game whils showing
	tempData->write<double>(this->dataContainer->gameInformation.lastChanged); //Last changed
	tempData->writeString(this->dataContainer->gameInformation.gameInformationRTF); //Game information

	tempData->compressData(); //Compress this whole block
	data->write<int>(tempData->getLength()); //Write length of block
	data->writeBytes(tempData->getBuffer(),tempData->getLength()); //Write the block
	delete tempData; //Delete the buffer
}

void GMK80Writer::writeIncludedFile(dataStream *data, includedFilesDef *dataWrite) {
	dataStream * tempData = new dataStream(); //Temporary buffer

		tempData->write<double>(dataWrite->lastChanged); //Last time changed
		tempData->write<int>(800); //GM version needed for the following info
		tempData->writeString(dataWrite->fileName); //File name
		tempData->writeString(dataWrite->filePath); //File path
		tempData->writeBool4(dataWrite->originalFile); //Original file?
		tempData->write<int>(dataWrite->originalFileSize); //Original file size?
		tempData->writeBool4(dataWrite->storedInGMK); //Store in GMK?
		if (dataWrite->storedInGMK==true)
		{
			tempData->writeBytes(dataWrite->fileData->getBuffer(),dataWrite->fileData->getLength()); //Write the file data
		}
		tempData->write<int>(dataWrite->exportType); //Export type
		tempData->writeString(dataWrite->folderExport); //Folder to export to
		tempData->writeBool4(dataWrite->overWrite); //Overwrite if file exists..
		tempData->writeBool4(dataWrite->freeMem); //Free memory after export;
		tempData->writeBool4(dataWrite->removeGameEnd); //Remove the file at game end?

	tempData->compressData(); //Compress this whole block
	data->write<int>(tempData->getLength()); //Write length of block
	data->writeBytes(tempData->getBuffer(),tempData->getLength()); //Write the block
	delete tempData; //Delete the buffer
}

void GMK80Writer::writeTrigger(dataStream *data, triggerDef *dataWrite) {
	dataStream * tempData = new dataStream(); //Temporary buffer

		tempData->writeBool4(true); //Weather the trigger exists or not..
		tempData->write<int>(800); //GM version needed for the following info
		tempData->writeString(dataWrite->Name); //Name of the trigger
		tempData->writeString(dataWrite->Condition); //Condition for the trigger
		tempData->write<int>(dataWrite->checkMoment); //Moment to check
		tempData->writeString(dataWrite->constantName); //Constant Name

	tempData->compressData(); //Compress this whole block
	data->write<int>(tempData->getLength()); //Write length of block
	data->writeBytes(tempData->getBuffer(),tempData->getLength()); //Write the block
	delete tempData; //Delete the buffer
}

void GMK80Writer::writeSound(dataStream *data, soundDef *dataWrite) {
	dataStream * tempData = new dataStream(); //Temporary buffer

		tempData->writeBool4(true); //If this resoure exists
		tempData->writeString(dataWrite->Name); //Name of the resource
		tempData->write<double>(dataWrite->lastChanged); //Last time changed
		tempData->write<int>(800); //GM version needed for the following info
		tempData->write<int>(dataWrite->Kind); //Kind of sound
		tempData->writeString(dataWrite->fileType); //File Type (Extention..)
		tempData->writeString(dataWrite->fileName); //File name without directory
		if (dataWrite->musicData==NULL)
		{
			tempData->writeBool4(false); //Sound does not exist
		}else{
			tempData->writeBool4(true); //Sound exists
			tempData->write<int>(dataWrite->musicData->getLength()); //Write the size
			tempData->writeBytes(dataWrite->musicData->getBuffer(),dataWrite->musicData->getLength()); //Write the sound data
		}
		tempData->write<int>(dataWrite->Effects); //Effects applied to the sound
		tempData->write<double>(dataWrite->volume); //Volume;
		tempData->write<double>(dataWrite->Pan); //Pan
		tempData->writeBool4(dataWrite->preload);// Preload the sound?

	tempData->compressData(); //Compress this whole block
	data->write<int>(tempData->getLength()); //Write length of block
	data->writeBytes(tempData->getBuffer(),tempData->getLength()); //Write the block
	delete tempData; //Delete the buffer
}

void GMK80Writer::writeSprite(dataStream *data, spriteDef *dataWrite) {
	dataStream * tempData = new dataStream(); //Temporary buffer

			tempData->writeBool4(true); //If this sprite exists
			tempData->writeString(dataWrite->Name); //Name of the sprite
			tempData->write<double>(dataWrite->lastChanged); //Last time it was modified
			tempData->write<int>(800); //GM Version needed for the folllowing info
			tempData->write<int>(dataWrite->originX); //X origin
			tempData->write<int>(dataWrite->originY); //Y Origin
			tempData->write<int>(dataWrite->subImages.size()); //Write how many sub images their are
			for (unsigned int si=0; si<dataWrite->subImages.size(); si++)
			{//For each sub image
				tempData->write<int>(800); //GM Version needed for the following info
				tempData->write<int>(dataWrite->subImages[si]->Width); //Width
				tempData->write<int>(dataWrite->subImages[si]->Height); //Height
				if (dataWrite->subImages[si]->Width!=0 && dataWrite->subImages[si]->Height!=0)
				{
					tempData->write<int>(dataWrite->subImages[si]->imageData->getLength()); //Write the size
					tempData->writeBytes(dataWrite->subImages[si]->imageData->getBuffer(),dataWrite->subImages[si]->imageData->getLength()); //Write the sprite data
				}
			}//For each sub image
			tempData->write<int>(dataWrite->shape); //Shape
			tempData->write<int>(dataWrite->alphaTolerance); //Alpha tolerance
			tempData->writeBool4(dataWrite->seperateCollisionMasks); //Seperate collision masks?
			tempData->write<int>(dataWrite->boundingBox); //bounding box
			tempData->write<int>(dataWrite->Left); //BB Left
			tempData->write<int>(dataWrite->Right); //BB Right
			tempData->write<int>(dataWrite->Bottom); //BB Bottom
			tempData->write<int>(dataWrite->Top); //BB Top

	tempData->compressData(); //Compress this whole block
	data->write<int>(tempData->getLength()); //Write length of block
	data->writeBytes(tempData->getBuffer(),tempData->getLength()); //Write the block
	delete tempData; //Delete the buffer
}

void GMK80Writer::writeBackground(dataStream *data, backgroundDef *dataWrite) {
	dataStream * tempData = new dataStream(); //Temporary buffer

		tempData->writeBool4(true); //If this bg exists
		tempData->writeString(dataWrite->Name); //BG NAme
		tempData->write<double>(dataWrite->lastChanged); //Last changed
		tempData->write<int>(710); //GM Version needed for the following info
		tempData->writeBool4(dataWrite->tileSet); //Is a tile set?
		tempData->write<int>(dataWrite->tileWidth); //Tile width
		tempData->write<int>(dataWrite->tileHeight); //Tile height
		tempData->write<int>(dataWrite->hOffset); //horizontal offset
		tempData->write<int>(dataWrite->vOffset); //Vertical ofset
		tempData->write<int>(dataWrite->hSep); // Whore. seperation
		tempData->write<int>(dataWrite->vSep); //Vert. seperatopn
		tempData->write<int>(800); //GM Version needed for the following info
		tempData->write<int>(dataWrite->Width); //Width
		tempData->write<int>(dataWrite->Height); //Heigt
		if (dataWrite->Width!=0 && dataWrite->Height!=0)
		{
			tempData->write<int>(dataWrite->imageData->getLength()); //Write the length of the data
			tempData->writeBytes(dataWrite->imageData->getBuffer(),dataWrite->imageData->getLength()); //Write the background image
		}

	tempData->compressData(); //Compress this whole block
	data->write<int>(tempData->getLength()); //Write length of block
	data->writeBytes(tempData->getBuffer(),tempData->getLength()); //Write the block
	delete tempData; //Delete the buffer
}

void GMK80Writer::writePath(dataStream *data, pathDef *dataWrite) {
	dataStream * tempData = new dataStream(); //Temporary buffer

		tempData->writeBool4(true); //If this path exists
		tempData->writeString(dataWrite->Name); //Write the name
		tempData->write<double>(dataWrite->lastChanged); //Last modified
		tempData->write<int>(530); //GM Version required
		tempData->write<int>(dataWrite->Kind); //Connection kind
		tempData->writeBool4(dataWrite->Closed);//Closed?
		tempData->write<int>(dataWrite->Precision); //Precision
		tempData->write<int>(dataWrite->roomIndexBG); //Room index to show as BG
		tempData->write<int>(dataWrite->snapX); //Snap X
		tempData->write<int>(dataWrite->snapY); //Snap Y
		tempData->write<int>(dataWrite->Points.size()); //How many points their are
		for(unsigned int pi=0; pi<dataWrite->Points.size(); pi++) {
			tempData->write<double>(dataWrite->Points[pi]->x);
			tempData->write<double>(dataWrite->Points[pi]->y);
			tempData->write<double>(dataWrite->Points[pi]->speed);
		}

	tempData->compressData(); //Compress this whole block
	data->write<int>(tempData->getLength()); //Write length of block
	data->writeBytes(tempData->getBuffer(),tempData->getLength()); //Write the block
	delete tempData; //Delete the buffer
}

void GMK80Writer::writeScript(dataStream *data, scriptDef *dataWrite) {
	dataStream * tempData = new dataStream(); //Temporary buffer

		tempData->writeBool4(true); //If this Script exists
		tempData->writeString(dataWrite->Name); //Name of the script
		tempData->write<double>(dataWrite->lastChanged); //Last modified
		tempData->write<int>(800); //GM 8.0 needed
		tempData->writeString(dataWrite->Script); //Script as text..

	tempData->compressData(); //Compress this whole block
	data->write<int>(tempData->getLength()); //Write length of block
	data->writeBytes(tempData->getBuffer(),tempData->getLength()); //Write the block
	delete tempData; //Delete the buffer
}

void GMK80Writer::writeFont(dataStream *data, fontDef *dataWrite) {
	dataStream * tempData = new dataStream(); //Temporary buffer

		tempData->writeBool4(true); //If this Font exists
		tempData->writeString(dataWrite->Name); //Write the NAme
		tempData->write<double>(dataWrite->lastChanged); //Last modified
		tempData->write<int>(800); //GM Version needed for the following info
		tempData->writeString(dataWrite->fontName); //Font name
		tempData->write<int>(dataWrite->Size); //Size
		tempData->writeBool4(dataWrite->Bold); //Bold?
		tempData->writeBool4(dataWrite->Italic); //Italic?
		tempData->write<int>(dataWrite->charRangeBegin); //Character range begin
		tempData->write<int>(dataWrite->charRangeEnd); //Character Range end

	tempData->compressData(); //Compress this whole block
	data->write<int>(tempData->getLength()); //Write length of block
	data->writeBytes(tempData->getBuffer(),tempData->getLength()); //Write the block
	delete tempData; //Delete the buffer
}

void GMK80Writer::writeTimeline(dataStream *data, timelineDef *dataWrite) {
	dataStream * tempData = new dataStream(); //Temporary buffer

	tempData->writeBool4(true); //If this Timeline exists
	tempData->writeString(dataWrite->TimelineName); //Name of the timeline
	tempData->write<double>(dataWrite->lastChanged); //Last modified
	tempData->write<int>(500); //GM Version needed
	tempData->write<int>(dataWrite->momentList.size()); //How many moments their are.
	for (unsigned int mi=0; mi<dataWrite->momentList.size(); mi++)
	{//For each moment
		tempData->write<int>(dataWrite->momentList[mi]->moment); //The moment in time..
		tempData->write<int>(400); //GM Version needed for the following info
		tempData->write<int>(dataWrite->momentList[mi]->actionsList.size()); //How many actions it has
		for(unsigned int ai=0; ai<dataWrite->momentList[mi]->actionsList.size(); ai++)
		{//For each action
			tempData->write<int>(440); //GM Version needed for the following info
			tempData->write<int>(dataWrite->momentList[mi]->actionsList[ai]->libraryID); //Library ID
			tempData->write<int>(dataWrite->momentList[mi]->actionsList[ai]->ID); //Action ID
			tempData->write<int>(dataWrite->momentList[mi]->actionsList[ai]->Kind); //Kind
			tempData->writeBool4(dataWrite->momentList[mi]->actionsList[ai]->maybeRelative); //May be relative
			tempData->writeBool4(dataWrite->momentList[mi]->actionsList[ai]->Question); //Is a question
			tempData->writeBool4(dataWrite->momentList[mi]->actionsList[ai]->appliesToSomething); //Applies to something
			tempData->write<int>(dataWrite->momentList[mi]->actionsList[ai]->Type); //Type of action
			tempData->writeString(dataWrite->momentList[mi]->actionsList[ai]->functionName); //Function name
			tempData->writeString(dataWrite->momentList[mi]->actionsList[ai]->functionCode); //Function code
			tempData->write<int>(dataWrite->momentList[mi]->actionsList[ai]->argumentsUsed); //How many arguments are used
			tempData->write<int>(8); //How many arguments there are
			for(unsigned char ak=0; ak<8; ak++)
			{//Write the argument kinds
				tempData->write<int>(dataWrite->momentList[mi]->actionsList[ai]->argumentKind[ak]);
			}
			tempData->write<int>(dataWrite->momentList[mi]->actionsList[ai]->appliesToObject); //Object it applies to
			tempData->writeBool4(dataWrite->momentList[mi]->actionsList[ai]->isRelative); //Is relative
			tempData->write<int>(8); //How many arguments there are
			for(unsigned char ak=0; ak<8; ak++)
			{//Write the argument kinds
				tempData->writeString(dataWrite->momentList[mi]->actionsList[ai]->argumentValues[ak]);
			}
			tempData->write<int>(-1); //End of an event type..	
		}//For each action

	}

	tempData->compressData(); //Compress this whole block
	data->write<int>(tempData->getLength()); //Write length of block
	data->writeBytes(tempData->getBuffer(),tempData->getLength()); //Write the block
	delete tempData; //Delete the buffer
}

void GMK80Writer::writeObject(dataStream *data, objectDef *dataWrite) {
	dataStream * tempData = new dataStream(); //Temporary buffer

		tempData->writeBool4(true); //If this Timeline exists
		tempData->writeString(dataWrite->Name); //Name of object
		tempData->write<double>(dataWrite->lastChanged); //Last modified
		tempData->write<int>(430); //GM Version needed for the following info..
		tempData->write<int>(dataWrite->spriteIndex); //Sprite index
		tempData->writeBool4(dataWrite->Solid); //Solid?
		tempData->writeBool4(dataWrite->Visible); //Visible?
		tempData->write<int>(dataWrite->Depth); //Depth
		tempData->writeBool4(dataWrite->Persistent); //Persistent?
		tempData->write<int>(dataWrite->parentObject); //Parent object index
		tempData->write<int>(dataWrite->maskSpriteIndex); //Mask sprite index
		tempData->write<int>(11); //How many event types their are..
		for(unsigned char ev=0; ev<12; ev++)
		{//For the 11 main event types
			for (unsigned int evm=0; evm<dataWrite->Events.size(); evm++)
			{//For each event
				if (dataWrite->Events[evm]->eventType==ev)
				{//If this event belongs to this kind
					tempData->write<int>(dataWrite->Events[evm]->eventKind); //Kind (numb) of event
					tempData->write<int>(400); //GM Version needed for the following info
					tempData->write<int>(dataWrite->Events[evm]->Actions.size()); //How many actions
					for(unsigned int ai=0; ai<dataWrite->Events[evm]->Actions.size(); ai++)
					{//For each action
						tempData->write<int>(440); //GM Version needed for the following info
						tempData->write<int>(dataWrite->Events[evm]->Actions[ai]->libraryID); //Library ID
						tempData->write<int>(dataWrite->Events[evm]->Actions[ai]->ID); //Action ID
						tempData->write<int>(dataWrite->Events[evm]->Actions[ai]->Kind); //Kind
						tempData->writeBool4(dataWrite->Events[evm]->Actions[ai]->maybeRelative); //May be relative
						tempData->writeBool4(dataWrite->Events[evm]->Actions[ai]->Question); //Is a question
						tempData->writeBool4(dataWrite->Events[evm]->Actions[ai]->appliesToSomething); //Applies to something
						tempData->write<int>(dataWrite->Events[evm]->Actions[ai]->Type); //Type of action
						tempData->writeString(dataWrite->Events[evm]->Actions[ai]->functionName); //Function name
						tempData->writeString(dataWrite->Events[evm]->Actions[ai]->functionCode); //Function code
						tempData->write<int>(dataWrite->Events[evm]->Actions[ai]->argumentsUsed); //How many arguments are used
						tempData->write<int>(8); //How many arguments there are
						for(unsigned char ak=0; ak<8; ak++)
						{//Write the argument kinds
							tempData->write<int>(dataWrite->Events[evm]->Actions[ai]->argumentKind[ak]);
						}
						tempData->write<int>(dataWrite->Events[evm]->Actions[ai]->appliesToObject); //Object it applies to
						tempData->writeBool4(dataWrite->Events[evm]->Actions[ai]->isRelative); //Is relative
						tempData->write<int>(8); //How many arguments there are
						for(unsigned char ak=0; ak<8; ak++)
						{//Write the argument kinds
							tempData->writeString(dataWrite->Events[evm]->Actions[ai]->argumentValues[ak]);
						}
							tempData->write<int>(-1); //End of an event type..	
					}//For each action
					
				}//If this event belongs the current main event we are iterating

					
			}//For the main events
			tempData->write<int>(-1); //End of an event type..	
		}

	tempData->compressData(); //Compress this whole block
	data->write<int>(tempData->getLength()); //Write length of block
	data->writeBytes(tempData->getBuffer(),tempData->getLength()); //Write the block
	delete tempData; //Delete the buffer
}

void GMK80Writer::writeRoom(dataStream *data, roomDef *dataWrite) {
	dataStream * tempData = new dataStream(); //Temporary buffer

		tempData->writeBool4(true); //If this room exists
		tempData->writeString(dataWrite->Name); //Write the name
		tempData->write<double>(dataWrite->lastChanged); //Last modified
		tempData->write<int>(541); //GM Version needed
		tempData->writeString(dataWrite->roomCaption); //Caption string
		tempData->write<int>(dataWrite->Width); //Width
		tempData->write<int>(dataWrite->Height); //Height
		tempData->write<int>(dataWrite->snapX); //Snap X
		tempData->write<int>(dataWrite->snapY); //Snap Y
		tempData->writeBool4(dataWrite->isometricGrid); //Isometric grid?
		tempData->write<int>(dataWrite->Speed); //Speed
		tempData->writeBool4(dataWrite->Persistent); //Persistent?
		tempData->write<int>(dataWrite->backgroundColor); //Background color
		tempData->writeBool4(dataWrite->drawBackgroundColor); //Draw BG color
		tempData->writeString(dataWrite->creationCode);//Creation code
		tempData->write<int>(8); //Amount of bgs
		for(unsigned int bgs=0; bgs<8; bgs++)
		{//for each BG
			if (bgs<dataWrite->Backgrounds.size())
			{
				tempData->writeBool4(dataWrite->Backgrounds[bgs]->Visible); //Visible when room starts?
				tempData->writeBool4(dataWrite->Backgrounds[bgs]->foregroundImage); //Is forgreound?
				tempData->write<int>(dataWrite->Backgrounds[bgs]->backgroundIndex); //Index of BG
				tempData->write<int>(dataWrite->Backgrounds[bgs]->X); // X position
				tempData->write<int>(dataWrite->Backgrounds[bgs]->Y); //Y position
				tempData->writeBool4(dataWrite->Backgrounds[bgs]->tileH); //Tile hor
				tempData->writeBool4(dataWrite->Backgrounds[bgs]->tileV); //Tile V
				tempData->write<int>(dataWrite->Backgrounds[bgs]->hSpeed); //Hspeed
				tempData->write<int>(dataWrite->Backgrounds[bgs]->vSpeed); //Vspeed
				tempData->writeBool4(dataWrite->Backgrounds[bgs]->Stretch); //Stretch?
			}else{
				//Write default information for this bg
				tempData->writeBool4(false); //Visible when room starts?
				tempData->writeBool4(false); //Is forgreound?
				tempData->write<int>(-1); //Index of BG
				tempData->write<int>(0); // X position
				tempData->write<int>(0); //Y position
				tempData->writeBool4(true); //Tile hor
				tempData->writeBool4(true); //Tile V
				tempData->write<int>(0); //Hspeed
				tempData->write<int>(0); //Vspeed
				tempData->writeBool4(false); //Stretch?
			}
		}
		tempData->writeBool4(dataWrite->enableViews); //Enable the use of views?
		tempData->write<int>(8); //Amount of views
		for (unsigned int v=0; v<8; v++)
		{
			if (v<dataWrite->Views.size())
			{
				tempData->writeBool4(dataWrite->Views[v]->visibleStart); //Visible when room starts?
				tempData->write<int>(dataWrite->Views[v]->viewX); //XPosition
				tempData->write<int>(dataWrite->Views[v]->viewY); //Y position
				tempData->write<int>(dataWrite->Views[v]->viewW); //View Width
				tempData->write<int>(dataWrite->Views[v]->viewH); //View height
				tempData->write<int>(dataWrite->Views[v]->portX); //Port X
				tempData->write<int>(dataWrite->Views[v]->portY);//Port Y
				tempData->write<int>(dataWrite->Views[v]->portW); //Port width
				tempData->write<int>(dataWrite->Views[v]->portH); //port height
				tempData->write<int>(dataWrite->Views[v]->hBorder); //H border
				tempData->write<int>(dataWrite->Views[v]->vBorder); //V border
				tempData->write<int>(dataWrite->Views[v]->Hsp); //H speed
				tempData->write<int>(dataWrite->Views[v]->Vsp); //V speed
				tempData->write<int>(dataWrite->Views[v]->objFollow); //Index of object to follow
			}else{
				//Write default information..
				tempData->writeBool4(false); //Visible when room starts?
				tempData->write<int>(0); //XPosition
				tempData->write<int>(0); //Y position
				tempData->write<int>(640); //View Width
				tempData->write<int>(480); //View height
				tempData->write<int>(0); //Port X
				tempData->write<int>(0);//Port Y
				tempData->write<int>(640); //Port width
				tempData->write<int>(480); //port height
				tempData->write<int>(32); //H border
				tempData->write<int>(32); //V border
				tempData->write<int>(-1); //H speed
				tempData->write<int>(-1); //V speed
				tempData->write<int>(-1); //Index of object to follow
			}
		}
		tempData->write<int>(dataWrite->Instances.size()); //How many instances their are
		for (unsigned int ip=0; ip<dataWrite->Instances.size(); ip++)
		{
			tempData->write<int>(dataWrite->Instances[ip]->X); //X position
			tempData->write<int>(dataWrite->Instances[ip]->Y); //Y Position
			tempData->write<int>(dataWrite->Instances[ip]->objectIndex); //Object index
			tempData->write<int>(dataWrite->Instances[ip]->ID); //Instance ID
			tempData->writeString(dataWrite->Instances[ip]->creationCode); //Creation code
			tempData->writeBool4(dataWrite->Instances[ip]->Locked); //Locked?
		}
		tempData->write<int>(dataWrite->Tiles.size()); //How many tiles are in the room
		for (unsigned int t=0; t<dataWrite->Tiles.size(); t++)
		{//For each tile..........
			tempData->write<int>(dataWrite->Tiles[t]->X); //X position
			tempData->write<int>(dataWrite->Tiles[t]->Y); //Y position
			tempData->write<int>(dataWrite->Tiles[t]->backgroundIndex); //BG index
			tempData->write<int>(dataWrite->Tiles[t]->tileX); //TileX
			tempData->write<int>(dataWrite->Tiles[t]->tileY); //TileY
			tempData->write<int>(dataWrite->Tiles[t]->Width); //Width
			tempData->write<int>(dataWrite->Tiles[t]->Height); //Heigt
			tempData->write<int>(dataWrite->Tiles[t]->Depth); //Depth/layer
			tempData->write<int>(dataWrite->Tiles[t]->ID); //Tile ID
			tempData->writeBool4(dataWrite->Tiles[t]->Locked); //Locked?
		}
		tempData->writeBool4(dataWrite->rememberRoomEditorInfo); //Remember info?
		tempData->write<int>(dataWrite->roomEditorWidth); //Width of room editor
		tempData->write<int>(dataWrite->roomEditorHeight); //Room editor height
		tempData->writeBool4(dataWrite->showGrid); //Show grid?
		tempData->writeBool4(dataWrite->showObjects); //Show objects?
		tempData->writeBool4(dataWrite->showTiles); //Show tiles?
		tempData->writeBool4(dataWrite->showBackgrounds); //Show backgrounds?
		tempData->writeBool4(dataWrite->showForegrounds); //Show forgrounds?
		tempData->writeBool4(dataWrite->showViews); //Show views?
		tempData->writeBool4(dataWrite->deleteUnderlyingObjects); //Delete underlying objects
		tempData->writeBool4(dataWrite->deleteUnderlyingTiles); //Delete underlying tiles
		tempData->write<int>(dataWrite->Tab); //What tab is active
		tempData->write<int>(dataWrite->xPosScrollBar); //X position of the scroll bar
		tempData->write<int>(dataWrite->yPosScrollBar); //Y position of the scroll bar

	tempData->compressData(); //Compress this whole block
	data->write<int>(tempData->getLength()); //Write length of block
	data->writeBytes(tempData->getBuffer(),tempData->getLength()); //Write the block
	delete tempData; //Delete the buffer
}

void GMK80Writer::writeNullResource(dataStream *data) {
	dataStream * tempData = new dataStream(); //Temporary buffer

		tempData->writeBool4(false); //Resource doesnt exist.

	tempData->compressData(); //Compress this whole block
	data->write<int>(tempData->getLength()); //Write length of block
	data->writeBytes(tempData->getBuffer(),tempData->getLength()); //Write the block
	delete tempData; //Delete the buffer
}